﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GA.Server.Api;
using System.Threading;

namespace GA.Server.Main.Actions
{
    public class ShutdownAction : IConsoleAction
    {

        public string Name
        {
            get { return "Shutdown"; }
        }

        public string HelpInfo
        {
            get
            {
                StringBuilder help = new StringBuilder();
                help.AppendLine("Shutdown Command:");
                help.AppendLine(" USAGE: Shutdown [<ForceShutdownTime>] [<MaxWaitTime>]");
                help.AppendLine(" DESCRIPTION: Stops all servers and ends the service.");
                help.AppendLine(" ForceShutdownTime: Optional, but must be in the TimeSpan Format (HH:mm:ss)");
                return help.ToString();
            }
        }

        public ConsoleActionResult RunAction(string param)
        {
            TimeSpan forceShutdownTime = TimeSpan.FromSeconds(30);
            TimeSpan maxWaitTime = TimeSpan.FromSeconds(60);
            if (param != null && param.Length > 0)
            {
                string[] parameters = param.Split(' ');
                TimeSpan.TryParse(parameters[0], out forceShutdownTime);
                if (parameters.Length > 1)
                {
                    TimeSpan.TryParse(parameters[1], out maxWaitTime);
                }
            }

            IEnumerable<GAServer> servers = Program.CurrentProgram.RunningServers;
            foreach (GAServer server in servers)
            {
                Console.WriteLine(string.Format("Shutting down server {0}.", server.Name));
                server.Stop(false);
            }

            DateTime beginWait = DateTime.Now;
            while (servers.Any((server) =>
                {
                    return server.Status != GAServerStatus.Stopped
                        && server.Status != GAServerStatus.Failed
                        && server.Status != GAServerStatus.Disposed;
                })
                && DateTime.Now.Subtract(beginWait) < forceShutdownTime)
            {
                Thread.Sleep(50);
            }
            if (servers.Any((server) =>
                {
                    return server.Status != GAServerStatus.Stopped
                        && server.Status != GAServerStatus.Failed
                        && server.Status != GAServerStatus.Disposed;
                }))
            {
                IEnumerable<GAServer> remainingServers = servers.TakeWhile((server) =>
                {
                    return server.Status != GAServerStatus.Stopped
                        && server.Status != GAServerStatus.Failed
                        && server.Status != GAServerStatus.Disposed;
                });
                foreach (GAServer server in remainingServers)
                {
                    Console.WriteLine(string.Format("Server {0} did not shut down after {1}. Forcing shutdown...", server.Name, forceShutdownTime));
                    server.Stop(true);
                }
                while (remainingServers.Any((server) =>
                {
                    return server.Status != GAServerStatus.Stopped
                        && server.Status != GAServerStatus.Failed
                        && server.Status != GAServerStatus.Disposed;
                })
                && DateTime.Now.Subtract(beginWait) < maxWaitTime)
                {
                    Thread.Sleep(50);
                }
                if (remainingServers.Any((server) =>
                    {
                        return server.Status != GAServerStatus.Stopped
                            && server.Status != GAServerStatus.Failed
                            && server.Status != GAServerStatus.Disposed;
                    }))
                {
                    Console.WriteLine(string.Format("{0} servers were still running after force shutdown was called. Killing entire service may corrupt data. Force shutdown service (y/n)?", remainingServers.Count()));
                    ConsoleKeyInfo consoleKeyInfo = Console.ReadKey();
                    if (consoleKeyInfo.KeyChar == 'n')
                    {
                        return ConsoleActionResult.Error;
                    }
                }
            }
            Console.WriteLine("Server is shutting down.");
            return ConsoleActionResult.RequestShutdown;
        }
    }
}
